/*
 * @(#)Main.java     14/08/02
 * 
 * Author             Rick Wilson
 * Copyright (c) 2014 Rick Wilson
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of 'Taareekah' nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */



package core;

//~--- non-JDK imports --------------------------------------------------------

import com.jme3.app.SimpleApplication;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.RenderManager;
import com.jme3.terrain.geomipmap.TerrainQuad;

import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.NiftyEventAnnotationProcessor;
import de.lessvoid.nifty.NiftyEventSubscriber;
import de.lessvoid.nifty.controls.ButtonClickedEvent;

import parameters.Parameters;

import gui.GenerateWorldScreen;
import gui.GenerationParametersScreen;
import gui.StartScreenState;
import gui.WorldViewerScreen;

import world.World;

import worldgeneration.WorldGenerator;

//~--- JDK imports ------------------------------------------------------------

import java.io.File;
import java.io.IOException;

import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;

/**
 * The entry point for the application. Also implements the start screen's
 * callbacks.
 * @author Rick Wilson
 */
public class Main extends SimpleApplication {

    /** Field description */
    private static World	world	= null;

    /** Field description */
    private static GameScriptManager	gsm;

    /** Field description */
    private WorldGenerator	world_gen	= null;

    /** Field description */
    private Nifty	nifty;

    /** Field description */
    private TerrainQuad	terrain;

    /** Field description */
    private StartScreenState	start_screen;

    /**
     * Returns the world.
     * @return The world.
     */
    public static World getWorld() {
	return world;
    }

    /**
     * Returns the GameScriptManager.
     * @return GameScriptManager
     */
    public static GameScriptManager getScriptManager() {
	return gsm;
    }

    /**
     *
     * @param id
     * @param event
     */
    @NiftyEventSubscriber(id = "parameters_generate_button")
    public void generateWorldButtonHandler(String id, ButtonClickedEvent event) {
	try {
	    world	= new World(new File("saves/"));
	    world_gen	= new WorldGenerator(gsm);
	    world_gen.generate("FART");
	    world.initFromWorldGenerator(world_gen);
	    this.nifty.gotoScreen("world_viewer_screen");
	} catch (Exception e) {
	    Logger.getLogger(GenerateWorldScreen.class.getName()).log(Level.SEVERE, "Couldnt generate terrain", e);
	    stop();
	}
    }

    /**
     *
     * @param id
     * @param event
     */
    @NiftyEventSubscriber(id = "start_screen_load_world_button")
    public void loadWorldButtonHandler(String id, ButtonClickedEvent event) {
	try {
	    String	filename	= start_screen.getLoadWorldFilename();

	    world	= World.deserializeFromFile("saves/" + filename + "/world.ser", assetManager);
	    this.nifty.gotoScreen("world_viewer_screen");
	    Logger.getLogger(Main.class.getName()).log(Level.INFO, "Loaded world: {0}", filename);
	} catch (Exception e) {
	    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Couldnt load world {0}", e);
	    stop();
	}
    }

    /**
     * The main function.
     * @param args
     */
    public static void main(String[] args) {
	Main	app	= new Main();

	app.start();
    }

    /**
     * Method description
     *
     *
     * @return
     *
     * @throws Exception
     */
    private boolean initLogging() throws Exception {
	String		log_file	= System.getProperty("user.home") + File.separator + "log.log";
	Handler		fh		= new FileHandler(log_file);
	SimpleFormatter	formatter	= new SimpleFormatter();

	fh.setFormatter(formatter);
	Logger.getLogger("").addHandler(fh);
	Logger.getLogger("").setLevel(Level.FINE);
	Logger.getLogger("de").setLevel(Level.SEVERE);
	Logger.getLogger("org").setLevel(Level.SEVERE);

	return true;
    }

    /**
     * Method description
     *
     *
     * @return
     *
     * @throws Exception
     */
    private boolean initNifty() throws Exception {
	GenerateWorldScreen	gen_screen	= new GenerateWorldScreen(this);

	start_screen	= new StartScreenState(this);

	WorldViewerScreen		viewer_screen	= new WorldViewerScreen(this);
	GenerationParametersScreen	params_screen	= new GenerationParametersScreen();
	NiftyJmeDisplay			nifty_display	= new NiftyJmeDisplay(assetManager, inputManager,
							      audioRenderer, guiViewPort);

	nifty	= nifty_display.getNifty();

	try {
	    nifty.validateXml("Interface/screens.xml");
	} catch (Exception ex) {
	    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Couldnt validate startScreen.xml", ex);
	}

	nifty.fromXml("Interface/screens.xml", "start", start_screen, gen_screen, viewer_screen, params_screen);
	nifty.gotoScreen("start");
	guiViewPort.addProcessor(nifty_display);

	return true;
    }

    /**
     * Initializes the app. Creates GameScriptManager, loads global parameters,
     * and inits Nifty.
     */
    @Override
    public void simpleInitApp() {
	try {
	    initLogging();
	} catch (IOException ex) {
	    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
	} catch (SecurityException ex) {
	    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
	} catch (Exception ex) {
	    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
	}

	setDisplayStatView(false);
	setDisplayFps(false);

	try {
	    String[]	roots	= { "assets/Scripts" };

	    gsm	= new GameScriptManager(roots);
	    gsm.loadComponentClasses("assets" + File.separator + "GameObjects");
	} catch (Exception e) {
	    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Couldnt create GameScriptManager", e);
	    stop();
	}

	try {
	    Parameters.createParameterSet("general", "assets/GameDefs/standard_generation_parameters.xml");
	} catch (Exception ex) {
	    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
	}

	try {
	    initNifty();
	} catch (Exception ex) {
	    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Couldnt validate screens.xml", ex);
	    stop();
	}

	inputManager.setCursorVisible(true);
	flyCam.setDragToRotate(true);
	NiftyEventAnnotationProcessor.process(this);
    }

    /**
     *
     * @param tpf
     */
    @Override
    public void simpleUpdate(float tpf) {

	// TODO: add update code
    }

    /**
     *
     * @param rm
     */
    @Override
    public void simpleRender(RenderManager rm) {

	// TODO: add render code
    }
}


//~ Formatted by Jindent --- http://www.jindent.com
